﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GuoZhiQi.MiddleCache.Parameter
{
    public class CouchBaseInt : CouchBaseParameter<ulong>
    {
        #region Value.

        /// <summary>
        /// Get the value of current parameter.
        /// </summary>
        public override ulong Value
        {
            get;
            set;
        }

        #endregion Value.

        #region Constructor.

        public CouchBaseInt(CouchBaseObject parent, string paramKey)
            : base(parent, paramKey)
        {
            this.Value = 0;
        }

        #endregion Constructor.

        #region Atomic functions.

        /// <summary>
        /// Saves current value.
        /// </summary>
        /// <param name="client">Client.</param>
        /// <returns>Returns false if save failed.</returns>
        public override bool Set()
        {
            if (this.Key == null)
                throw new NullReferenceException("Key is not set yet.");

            ulong requestedValue = this.Value;
            bool success = false;
            this.Remove();

            if (this._expiresAfter.HasValue)
                this.Value = this.Client.Increment(this.Key, this.Value, 0, this._expiresAfter.Value);
            else if (this._expiresOn.HasValue)
                this.Value = this.Client.Increment(this.Key, this.Value, 0, this._expiresOn.Value);
            else
                this.Value = this.Client.Increment(this.Key, this.Value, 0);

            if (this.Value == requestedValue)
                success = true;

            this.JsonInSync = success;

            return success;
        }

        /// <summary>
        /// Refreshes current value.
        /// </summary>
        /// <param name="withTouch">If set to true, expiery date/timespan is refreshed on items. Make sure to set the expiery date/timespan before.</param>
        public override bool Refresh(bool withTouch = false)
        {
            if (this.Key == null)
                throw new NullReferenceException("Key is not set yet.");

            object retVal;
            this.JsonInSync = this.Client.TryGet(this.Key, out retVal);

            if (retVal != null)
                this.Value = ulong.Parse(retVal.ToString());
            else
                this.Value = 0;

            if (withTouch && this.JsonInSync)
            {
                if (this._expiresAfter.HasValue)
                    this.Client.Touch(this.Key, this._expiresAfter.Value);
                else if (this._expiresOn.HasValue)
                    this.Client.Touch(this.Key, this._expiresOn.Value);
            }

            return this.JsonInSync;
        }

        /// <summary>
        /// Increases value of parameter and refreshes with new value. Atomic function.
        /// </summary>
        /// <param name="client">Client.</param>
        /// <param name="incValue">Ammount for increase.</param>
        public void Increment(int incValue)
        {
            if (this.Key == null)
                throw new NullReferenceException("Key is not set yet.");

            this.Value = (uint)this.Client.Increment(this.Key, (ulong)this.Value, (ulong)incValue);
        }

        /// <summary>
        /// Decreases value of parameter and refreshes with new value. Atomic function.
        /// </summary>
        /// <param name="client">Client.</param>
        /// <param name="incValue">Ammount for increase.</param>
        public void Decrement(int decValue)
        {
            if (this.Key == null)
                throw new NullReferenceException("Key is not set yet.");

            this.Value = (uint)this.Client.Decrement(this.Key, (ulong)this.Value, (ulong)decValue);
        }

        #endregion Atomic functions.
    }
}
